package cc.itez.wx.linkman.service.impl;

import cc.itez.wx.linkman.service.MessageSender;
import cc.itez.wx.linkman.service.RoleService;
import cn.hutool.cache.Cache;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cc.itez.wx.linkman.mould.CmdInfo;
import cc.itez.wx.linkman.mould.Command;
import cc.itez.wx.linkman.mould.WxMessage;
import cc.itez.wx.linkman.service.MessageService;
import cc.itez.wx.linkman.val.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.ZoneId;
import java.util.*;

@Service
public class MessageServiceImpl implements MessageService {
    @Autowired
    MessageSender sender;
    @Autowired
    RoleService roleService;
    /**
     * Admin邀请码缓存
     * 有效时长5分钟
     */
    Cache<String, String> adminInviteCodeCache = new TimedCache<>(Duration.ofMinutes(5).toMillis());
    /**
     * 命令缓存空间
     * 有效时长5分钟
     */
    Cache<String, CmdInfo> commandSpace = new TimedCache<>(Duration.ofMinutes(5).toMillis());
    /**
     * 生成管理员邀请码
     */
    Command makeAdminInviteCode = new Command("/invite-admin", "邀请管理员", "使用此命令可以获取邀请码，将邀请码发送给被邀请者。被邀请者在本公众号中输入邀请码后，即可成为管理员。", msg -> {
        String inviteCode = UUID.fastUUID().toString();
        adminInviteCodeCache.put(inviteCode, msg.getFromUserName());
        return StrUtil.format("邀请码为：[AA-{}]\n请将上面的邀请码发送给被邀请者，被邀请者直接将邀请码输入到公众号对话框即可获得权限。\n邀请码有效时间：5分钟");
    });

    /**
     * 更换微信群邀请码
     */
    Command replaceWxInviteImage = new Command("/replace-invite-image", "更换微信群邀请码", "",
        // 触发更换命令
        msg -> {
            return "";
        },
        // 执行更换操作
        msg -> {
            return "";
        });
    /**
     * 获取当前时间日期
     */
    Command currentDateTime = new Command("/now", "当前日期时间", "获取当前时间（东八区/UTC+8）",
        msg -> DateUtil.convertTimeZone(new Date(),TimeZone.getTimeZone(ZoneId.of("UTC+8"))).toString("yyyy年MM月dd日 HH点mm分ss秒")
    );
    /**
     * 角色权限映射表
     */
    Map<Role, List<Command>> rolePermissions = new HashMap<>() {{
        put(Role.SUPER_ADMIN, Arrays.asList(makeAdminInviteCode, replaceWxInviteImage, currentDateTime));
        put(Role.ADMIN, Arrays.asList(replaceWxInviteImage, currentDateTime));
    }};

    @Override
    public String handler(WxMessage msg) {
        if (msg != null && msg.getMsgType() != null) {
            switch (msg.getMsgType()) {
                case TEXT -> {
                    return this.handlerTextMessage(msg);
                }
                case IMAGE -> {
                    return this.handlerImageMessage(msg);
                }
                case VOICE -> {
                    return sender.replyText(msg.getFromUserName(), "我还听不懂");
                }
                case VIDEO -> {
                    return sender.replyText(msg.getFromUserName(), "看不见");
                }
                case SHORT_VIDEO -> {
                    return sender.replyText(msg.getFromUserName(), "有意思");
                }
                case LOCATION -> {
                    return sender.replyText(msg.getFromUserName(), "我没长腿啊");
                }
                case LINK -> {
                    return sender.replyText(msg.getFromUserName(), "没钱交网费");
                }
            }
        }
        return "";
    }

    /**
     * 处理图片信息
     *
     * @param msg
     * @return
     */
    private String handlerImageMessage(WxMessage msg) {
        new Thread(){
            @Override
            public void run() {
                System.out.println(msg);
            }
        }.start();
        return sender.replyText(msg.getFromUserName(), "Image Message");
    }

    private String handlerTextMessage(WxMessage msg) {
        if (msg.getContent().startsWith("/")) {
            return sender.replyText(msg.getFromUserName(), this.handlerCommand(msg));
        } else if (msg.getContent().startsWith("AA-") && msg.getContent().length() == 39) {
            return this.addAdminWithInviteCode(msg);
        }
        return sender.replyText(msg.getFromUserName(), msg.getContent());
    }

    /**
     * 通过邀请码添加自己为管理员
     *
     * @param msg 用户消息
     *            - content: 邀请码
     *            - fromUserName: 请求成为管理员的用户
     */
    private String addAdminWithInviteCode(WxMessage msg) {
        return null;
    }

    /**
     * 处理命令
     */
    private String handlerCommand(WxMessage msg) {
        String content = msg.getContent();
        if (StrUtil.isNotEmpty(content)) {
            String cmd = StrUtil.subBefore(content, ' ', false).toLowerCase();
            String openId = msg.getFromUserName();
            Command command = findCommands(openId).get(cmd);
            if (command != null) {
                if (command.getSize() > 1) {
                    CmdInfo info = commandSpace.get(openId);
                    if (info == null) {
                        return command.func(0).apply(msg);
                    } else if (info.getNext() != null) {
                        return info.getNext().apply(msg);
                    } else {
                        commandSpace.remove(openId);
                        return info.getInfo();
                    }
                } else {
                    return command.func(0).apply(msg);
                }
            }
            return this.inviteCmd(cmd);
        }
        return "输入【/help】获取帮助";
    }

    private String inviteCmd(String cmd) {
        return StrUtil.format("无效的指令: {}\n输入【/help】获取帮助", cmd);
    }

    /**
     * 根据用户OpenId查找可用命令
     *
     * @param openId 微信OpenId
     */
    private Map<String, Command> findCommands(String openId) {
        Map<String, Command> commands = new TreeMap<>();
        Set<Role> roles = roleService.getUserRoles(openId);
        if (CollectionUtil.isNotEmpty(roles)) {
            for (Role role : roles) {
                List<Command> permissions = rolePermissions.get(role);
                if (CollectionUtil.isNotEmpty(permissions)) {
                    permissions.forEach(cmd -> {
                        commands.put(cmd.getCmd(), cmd);
                    });
                }
            }
        }
        return commands;
    }
}
